package com.lzs.system.common.controller;

import com.alibaba.fastjson.JSONObject;
import com.lzs.common.config.Constant;
import com.lzs.common.dto.LoginDto;
import com.lzs.common.config.JwtTokenUtil;
import com.lzs.common.enums.LoginValidateType;
import com.lzs.common.exception.LzsBusinessException;
import com.lzs.common.properties.MyProjectProperties;
import com.lzs.common.properties.RedisKeyProperties;
import com.lzs.common.service.UserAuthService;
import com.lzs.common.utils.SecurityUser;
import com.lzs.common.utils.SecurityUserUtils;
import com.lzs.common.utils.UUIDUtils;
import com.lzs.common.utils.img.ImageDragVerifyCodeUtils;
import com.lzs.common.utils.img.ImageTextVerifyCodeUtil;
import com.lzs.common.vo.GetImageDragVerifyCodeVo;
import com.lzs.common.vo.GetUserPowerVo;
import com.lzs.system.common.dto.MsgDto;
import com.lzs.common.vo.GetImageDragVerifyCodeVo;
import com.lzs.system.security.CustomUserDetailsService;
import com.lzs.common.service.SysMenuService;
import com.lzs.common.vo.CommonResult;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Objects;
import java.util.Random;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("userAuth")
@Slf4j
public class UserAuthController {

    @Autowired
    private CustomUserDetailsService userDetailsService;
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private SysMenuService sysMenuService;
    @Autowired
    private UserAuthService userAuthService;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private MyProjectProperties myProjectProperties;
    @Value("${spring.profiles.active}")
    private String activeProfile;



    @ApiOperation("登录验证类型")
    @GetMapping("getLoginValidateType")
    public CommonResult<LoginValidateType> loginValidateType(){
        return CommonResult.OK(Constant.LOGIN_VALIDATE_TYPE);
    }

    @PostMapping("sendInfo")
    public CommonResult sendInfo(@RequestBody MsgDto dto){
        WebSocketServer.sendInfo(dto,SecurityUserUtils.getSecurityUser().getUserId());
        String userId = SecurityUserUtils.getSecurityUser().getUserId();
        return CommonResult.OK(userId);
    }

    /**
     * 生成图片文字验证码
     */
    @ApiOperation("生成图片文字验证码")
    @GetMapping("getImageTextVerifyCode")
    public void getImageTextVerifyCode(String uid,HttpServletResponse response){
        response.setHeader("Pragma","No-cache");
        response.setHeader("Cache-Control","No-cache");
        response.setDateHeader("Expires",0);
        response.setContentType("image/jpeg");
        String strCode = "";
        Random random = new Random();
        for (int i = 0; i < 6; i++) {
            String strNumber = String.valueOf(random.nextInt(10));
            strCode += strNumber;
        }
        BufferedImage image= ImageTextVerifyCodeUtil.getCode(strCode);
        ValueOperations valueOperations = redisTemplate.opsForValue();
        RedisKeyProperties redisKey = myProjectProperties.getRedisKey();
        String inputVerifyCode = redisKey.getLoginImageInputVerifyCode();


        valueOperations.set(inputVerifyCode+uid,strCode,3,TimeUnit.MINUTES);
        ServletOutputStream outputStream = null;
        try {
            outputStream = response.getOutputStream();
            ImageIO.write(image,"JPEG", outputStream);
            outputStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (Objects.nonNull(outputStream)) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * @param @return 参数说明
     * @return BaseRestResult 返回类型
     * @Description: 生成滑块拼图验证码
     */
    @GetMapping(value = "getImageDragVerifyCode")
    public CommonResult<GetImageDragVerifyCodeVo> getImageVerifyCode() {
        String codeFileUrl = this.getClass().getResource("/image").getPath();
        if (!"dev".equals(activeProfile)) {
            codeFileUrl = myProjectProperties.getFile().getCodeFileUrl();
        }
        //读取本地路径下的图片,随机选一条
        log.info("codeFileUrl=[{}]",codeFileUrl);
        File file = new File(codeFileUrl);
        File[] files = file.listFiles();
        int n = new Random().nextInt(files.length);
        File imageUrl = files[n];
//        createImage(imageUrl, resultMap);

        //343*198
        //读取网络图片
//        GetImageDragVerifyCodeVo vo = ImageVerifyCodeUtils.createImage("https://img-blog.csdnimg.cn/20191223173355134.png");
        GetImageDragVerifyCodeVo vo = ImageDragVerifyCodeUtils.createImage(imageUrl);
        vo.setUid(UUIDUtils.generateUUID());
        log.info("偏移量高[{}]",vo.getH());
        log.info("偏移量宽[{}]",vo.getW());
        log.info("getSmallImage[{}]",vo.getSmallImage());
        ValueOperations valueOperations = redisTemplate.opsForValue();
        RedisKeyProperties redisKey = myProjectProperties.getRedisKey();
        String loginImageVerifyCode = redisKey.getLoginImageSlideVerifyCode();
        JSONObject json = new JSONObject();
        json.put("h",vo.getH());
        json.put("w",vo.getW());
        valueOperations.set(loginImageVerifyCode+vo.getUid(),json.toJSONString(),3, TimeUnit.MINUTES);
        vo.setH(0);
        vo.setW(0);
        return CommonResult.OK(vo);
    }
    //验证正负10个单位

    @PostMapping("login")
    public CommonResult authorize(@RequestBody LoginDto loginDto) {
        //需要验证
        if(Constant.LOGIN_VALIDATE_TYPE!=LoginValidateType.none){
            String uid = loginDto.getUid();
            ValueOperations valueOperations = redisTemplate.opsForValue();
            RedisKeyProperties redisKey = myProjectProperties.getRedisKey();
            String redisKeyStr = "";
            if (Constant.LOGIN_VALIDATE_TYPE==LoginValidateType.imageDrag){
                redisKeyStr = redisKey.getLoginImageSlideVerifyCode();
            }else if (Constant.LOGIN_VALIDATE_TYPE==LoginValidateType.viewPictureText){
                redisKeyStr = redisKey.getLoginImageInputVerifyCode();
            }
            Object codeObj = valueOperations.get(redisKeyStr + uid);
            if (Objects.isNull(codeObj)) {
                throw new LzsBusinessException("验证码不存在或已过期");
            }
            if (Constant.LOGIN_VALIDATE_TYPE== LoginValidateType.imageDrag) {
                JSONObject json = JSONObject.parseObject(codeObj.toString());
                //误差范围
                int errorRange = loginDto.getW() - json.getIntValue("w");
                if (errorRange>5||errorRange<-5){
                    throw new LzsBusinessException("请重试");
                }
                errorRange = loginDto.getH() - json.getIntValue("h");
                if (errorRange>5||errorRange<-5){
                    throw new LzsBusinessException("请重试");
                }
            }else if (Constant.LOGIN_VALIDATE_TYPE==LoginValidateType.viewPictureText){
                if (!codeObj.toString().equals(loginDto.getCode())){
                    throw new LzsBusinessException("验证码错误，请重试");
                }
            }
            redisTemplate.delete(redisKeyStr + uid);
        }


        // 创建Spring Security登录token
//        String password = "{bcrypt}"+loginDto.getPassword();
//        loginDto.setPassword(password);
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginDto.getUsername(), loginDto.getPassword());
        // 委托Spring Security认证组件执行认证过程
        Authentication authentication = authenticationManager.authenticate(authenticationToken);

        // 认证成功，设置上下文
        SecurityContextHolder.getContext().setAuthentication(authentication);
        // 生成jwt token
        Object principl = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        String userId = ((SecurityUser)principl).getUserId();

        String token = JwtTokenUtil.createToken(userId);
        //查询用户角色和权限

//        SysUserBo sysUserBo = new SysUserBo();
//        String uuid = UUIDUtils.generateUUID();
//        ValueOperations valueOperations = redisTemplate.opsForValue();
//        String sysUserBoJsonStr = JSON.toJSONString(sysUserBo);
//        valueOperations.set(uuid,sysUserBoJsonStr,30, TimeUnit.MINUTES);
        Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();

        return CommonResult.OK(token);
    }

    @GetMapping("info")
    public CommonResult info(){
//        SecurityUser securityUser = SecurityUserUtils.getSecurityUser().get();
        return userAuthService.getInfo();


//        list.add("admin");
//        map.put("roles", menuCodeList);
//        map.put("introduction", "I am a super administrator");
//        map.put("avatar", "https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif");
//        map.put("name", "Super Admin");
//        return CommonResult.OK();
    }

    public CommonResult getUserPower(){
        String userId = "";
        GetUserPowerVo getUserPowerVoList = userAuthService.getUserPower(userId);
        return CommonResult.OK();
    }

    /**
     * //todo 暂时返回所有的用户权限
     * 获取登陆用户菜单权限
     * @return
     */
    @ApiOperation("获取登陆用户菜单权限")
    @GetMapping("getLoginMenu")
    public CommonResult getLoginMenu(){
        return sysMenuService.getTreeMenuByRoleId("");
    }

    @PostMapping("logout")
    public CommonResult logout(){
        return CommonResult.OK();
    }

}
